1 /****************************** Module Header ******************************\
2 * Module Name: CppFileHandle.cpp
3 * Project: CppFileHandle
4 * Copyright (c) Microsoft Corporation.
6 * CppFileHandle demonstrates two typical scenarios of using file handles:
8 * 1) Enumerate file handles of a process
9 * 2) Get file name from a file handle
11 * This source is subject to the Microsoft Public License.
12 * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
13 * All other rights reserved.
15 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
16 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
18 \***************************************************************************/
20 #pragma region Includes
30 #define BUFFER_SIZE 512
33 #pragma region EnumerateFileHandles
35 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
36 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xc0000004L)
41 // Undocumented SYSTEM_INFORMATION_CLASS: SystemHandleInformation
42 const SYSTEM_INFORMATION_CLASS SystemHandleInformation
=
43 (SYSTEM_INFORMATION_CLASS
)16;
45 // The NtQuerySystemInformation function and the structures that it returns
46 // are internal to the operating system and subject to change from one
47 // release of Windows to another. To maintain the compatibility of your
48 // application, it is better not to use the function.
49 typedef NTSTATUS (WINAPI
* PFN_NTQUERYSYSTEMINFORMATION
)(
50 IN SYSTEM_INFORMATION_CLASS SystemInformationClass
,
51 OUT PVOID SystemInformation
,
52 IN ULONG SystemInformationLength
,
53 OUT PULONG ReturnLength OPTIONAL
57 #define HANDLE_TYPE_FILE 28
59 // Undocumented structure: SYSTEM_HANDLE_INFORMATION
60 typedef struct _SYSTEM_HANDLE
63 UCHAR ObjectTypeNumber
;
67 ACCESS_MASK GrantedAccess
;
68 } SYSTEM_HANDLE
, *PSYSTEM_HANDLE
;
70 typedef struct _SYSTEM_HANDLE_INFORMATION
72 ULONG NumberOfHandles
;
73 SYSTEM_HANDLE Handles
[1];
74 } SYSTEM_HANDLE_INFORMATION
, *PSYSTEM_HANDLE_INFORMATION
;
77 // Undocumented FILE_INFORMATION_CLASS: FileNameInformation
78 const FILE_INFORMATION_CLASS FileNameInformation
=
79 (FILE_INFORMATION_CLASS
)9;
81 // The NtQueryInformationFile function and the structures that it returns
82 // are internal to the operating system and subject to change from one
83 // release of Windows to another. To maintain the compatibility of your
84 // application, it is better not to use the function.
85 typedef NTSTATUS (WINAPI
* PFN_NTQUERYINFORMATIONFILE
)(
87 OUT PIO_STATUS_BLOCK IoStatusBlock
,
88 OUT PVOID FileInformation
,
90 IN FILE_INFORMATION_CLASS FileInformationClass
93 // FILE_NAME_INFORMATION contains name of queried file object.
94 typedef struct _FILE_NAME_INFORMATION
{
97 } FILE_NAME_INFORMATION
, *PFILE_NAME_INFORMATION
;
101 * Enumerate file handles of the specified process using undocumented APIs.
106 DWORD
EnumerateFileHandles(ULONG pid
)
108 /////////////////////////////////////////////////////////////////////////
109 // Prepare for NtQuerySystemInformation and NtQueryInformationFile.
112 // The functions have no associated import library. You must use the
113 // LoadLibrary and GetProcAddress functions to dynamically link to
116 HINSTANCE hNtDll
= LoadLibrary(_T("ntdll.dll"));
117 assert(hNtDll
!= NULL
);
119 PFN_NTQUERYSYSTEMINFORMATION NtQuerySystemInformation
=
120 (PFN_NTQUERYSYSTEMINFORMATION
)GetProcAddress(hNtDll
,
121 "NtQuerySystemInformation");
122 assert(NtQuerySystemInformation
!= NULL
);
124 PFN_NTQUERYINFORMATIONFILE NtQueryInformationFile
=
125 (PFN_NTQUERYINFORMATIONFILE
)GetProcAddress(hNtDll
,
126 "NtQueryInformationFile");
129 /////////////////////////////////////////////////////////////////////////
130 // Get system handle information.
133 DWORD nSize
= 4096, nReturn
;
134 PSYSTEM_HANDLE_INFORMATION pSysHandleInfo
= (PSYSTEM_HANDLE_INFORMATION
)
135 HeapAlloc(GetProcessHeap(), 0, nSize
);
137 // NtQuerySystemInformation does not return the correct required buffer
138 // size if the buffer passed is too small. Instead you must call the
139 // function while increasing the buffer size until the function no longer
140 // returns STATUS_INFO_LENGTH_MISMATCH.
141 while (NtQuerySystemInformation(SystemHandleInformation
, pSysHandleInfo
,
142 nSize
, &nReturn
) == STATUS_INFO_LENGTH_MISMATCH
)
144 HeapFree(GetProcessHeap(), 0, pSysHandleInfo
);
146 pSysHandleInfo
= (SYSTEM_HANDLE_INFORMATION
*)HeapAlloc(
147 GetProcessHeap(), 0, nSize
);
151 /////////////////////////////////////////////////////////////////////////
152 // Enumerate file handles of the process.
157 // Get the handle of the target process. The handle will be used to
158 // duplicate the file handles in the process.
159 HANDLE hProcess
= OpenProcess(
160 PROCESS_DUP_HANDLE
| PROCESS_QUERY_INFORMATION
, FALSE
, pid
);
161 if (hProcess
== NULL
)
163 _tprintf(_T("OpenProcess failed w/err 0x%08lx\n"), GetLastError());
167 for (ULONG i
= 0; i
< pSysHandleInfo
->NumberOfHandles
; i
++)
169 PSYSTEM_HANDLE pHandle
= &(pSysHandleInfo
->Handles
[i
]);
171 // Check for file handles of the specified process
172 if (pHandle
->ProcessId
== pid
&&
173 pHandle
->ObjectTypeNumber
== HANDLE_TYPE_FILE
)
175 dwFiles
++; // Increase the number of file handles
177 // Duplicate the handle in the current process
179 if (!DuplicateHandle(hProcess
, (HANDLE
)pHandle
->Handle
,
180 GetCurrentProcess(), &hCopy
, MAXIMUM_ALLOWED
, FALSE
, 0))
183 // Retrieve file name information about the file object.
184 IO_STATUS_BLOCK ioStatus
;
185 PFILE_NAME_INFORMATION pNameInfo
= (PFILE_NAME_INFORMATION
)
186 malloc(MAX_PATH
* 2 * 2);
187 DWORD dwInfoSize
= MAX_PATH
* 2 * 2;
188 if (NtQueryInformationFile(hCopy
, &ioStatus
, pNameInfo
,
189 dwInfoSize
, FileNameInformation
) == STATUS_SUCCESS
)
191 // Get the file name and print it
192 WCHAR wszFileName
[MAX_PATH
+ 1];
193 StringCchCopyNW(wszFileName
, MAX_PATH
+ 1,
194 pNameInfo
->FileName
, /*must be WCHAR*/
195 pNameInfo
->FileNameLength
/*in bytes*/ / 2);
197 wprintf(L
"0x%x:\t%s\n", pHandle
->Handle
, wszFileName
);
205 CloseHandle(hProcess
);
208 /////////////////////////////////////////////////////////////////////////
212 HeapFree(GetProcessHeap(), 0, pSysHandleInfo
);
214 // Return the number of file handles in the process
221 #pragma region GetFileNameFromHandle
224 * Get file name from a handle to a file object using a file mapping object.
225 * It uses the CreateFileMapping and MapViewOfFile functions to create the
226 * mapping. Next, it uses the GetMappedFileName function to obtain the file
227 * name. For remote files, it prints the device path received from this
228 * function. For local files, it converts the path to use a drive letter and
234 BOOL
GetFileNameFromHandle(HANDLE hFile
)
236 TCHAR szFileName
[MAX_PATH
+ 1];
240 DWORD dwFileSizeHi
= 0;
241 DWORD dwFileSizeLo
= GetFileSize(hFile
, &dwFileSizeHi
);
243 if (dwFileSizeLo
== 0 && dwFileSizeHi
== 0)
245 _tprintf(_T("Cannot map a file with a length of zero\n"));
249 /////////////////////////////////////////////////////////////////////////
250 // Create a file mapping object.
253 // Create a file mapping to get the file name
255 hFileMap
= CreateFileMapping(hFile
, NULL
, PAGE_READONLY
, 0, 1, NULL
);
258 _tprintf(_T("CreateFileMapping failed w/err 0x%08lx\n"),
263 void* pMem
= MapViewOfFile(hFileMap
, FILE_MAP_READ
, 0, 0, 1);
266 _tprintf(_T("MapViewOfFile failed w/err 0x%08lx\n"), GetLastError());
267 CloseHandle(hFileMap
);
272 /////////////////////////////////////////////////////////////////////////
273 // Call the GetMappedFileName function to obtain the file name.
276 if (GetMappedFileName(GetCurrentProcess(), pMem
, szFileName
, MAX_PATH
))
278 // szFileName contains device file name like:
279 // \Device\HarddiskVolume2\Users\JLG\AppData\Local\Temp\HLe6098.tmp
280 _tprintf(_T("Device name is %s\n"), szFileName
);
282 // Translate path with device name to drive letters.
283 TCHAR szTemp
[BUFFER_SIZE
];
286 // Get a series of null-terminated strings, one for each valid drive
287 // in the system, plus with an additional null character. Each string
288 // is a drive name. e.g. C:\\0D:\\0\0
289 if (GetLogicalDriveStrings(BUFFER_SIZE
- 1, szTemp
))
291 TCHAR szName
[MAX_PATH
];
292 TCHAR szDrive
[3] = _T(" :");
298 // Copy the drive letter to the template string
301 // Look up each device name. For example, given szDrive is C:,
302 // the output szName may be \Device\HarddiskVolume2.
303 if (QueryDosDevice(szDrive
, szName
, MAX_PATH
))
305 UINT uNameLen
= _tcslen(szName
);
307 if (uNameLen
< MAX_PATH
)
309 // Match the device name e.g. \Device\HarddiskVolume2
310 bFound
= _tcsnicmp(szFileName
, szName
, uNameLen
) == 0;
314 // Reconstruct szFileName using szTempFile
315 // Replace device path with DOS path
316 TCHAR szTempFile
[MAX_PATH
];
317 StringCchPrintf(szTempFile
, MAX_PATH
, _T("%s%s"),
318 szDrive
, szFileName
+ uNameLen
);
319 StringCchCopyN(szFileName
, MAX_PATH
+ 1,
320 szTempFile
, _tcslen(szTempFile
));
325 // Go to the next NULL character, i.e. the next drive name.
328 } while (!bFound
&& *p
); // End of string
333 /////////////////////////////////////////////////////////////////////////
334 // Clean up the file mapping object.
337 UnmapViewOfFile(pMem
);
338 CloseHandle(hFileMap
);
340 _tprintf(_T("File name is %s\n\n"), szFileName
);
347 int _tmain(int argc
, _TCHAR
* argv
[])
349 // Enumerate file handles of a process using undocumented APIs
350 ULONG pid
= GetCurrentProcessId();
351 DWORD dwFiles
= EnumerateFileHandles(pid
);
353 // Get file name from file handle using a file mapping object
354 /*HANDLE hFile = ...;
355 GetFileNameFromHandle(hFile);*/